package com.maigao.util;

import org.apache.commons.lang3.StringUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.Optional;

/**
 * @program: simulate
 * @description:
 * @author: yongza
 * @create: 2020-02-28 14:06
 **/
public class DateUtils {

    public static final LocalDateTime MIN_DATETIME = parse("0001-01-01 00:00:00", Formatter.DATETIME_YYYY_MM_DD_HH_MM_SS);
    public static final LocalDateTime MAX_DATETIME = parse("9999-12-31 23:59:59", Formatter.DATETIME_YYYY_MM_DD_HH_MM_SS);

    public enum DateUnit {
        // 年
        YEAR,
        // 月
        MONTH,
        // 日
        DAY,
        // 时
        HOUR,
        // 分
        MINUTE,
        // 秒
        SECOND,
        // 毫秒
        MILLIS
    }

    public enum Formatter {
        // yyyy-MM-dd
        DATE_YYYY_MM_DD("yyyy-MM-dd"),
        // yyyyMMdd
        DATE_YYYYMMDD("yyyyMMdd"),
        // yyyyMMddHHmm
        DATETIME_YYYYMMDDHHMM("yyyyMMddHHmm"),
        // yyyyMMddHHmm
        DATETIME_YYYYMMDDHHMMSS("yyyyMMddHHmmss"),
        // yyyy-MM-dd HH:mm
        DATETIME_YYYY_MM_DD_HH_MM("yyyy-MM-dd HH:mm"),
        // yyyy-MM-dd HH:mm:ss
        DATETIME_YYYY_MM_DD_HH_MM_SS("yyyy-MM-dd HH:mm:ss"),
        // yyyy-MM-dd HH:mm:ss SSS
        DATETIME_YYYY_MM_DD_HH_MM_SS_SSS("yyyy-MM-dd HH:mm:ss SSS"),
        // yyyyMMdd HHmmss
        DATETIME_YYYYMMDD_HHMMSS("yyyyMMdd HHmmss"),
        // yyyy-MM-dd#HH#mm
        DATETIME_YYYY_MM_DD_HHMM("yyyy-MM-dd'#'HH'#'mm"),
        // yyyyMMdd#HH#mm
        DATETIME_YYYYMMDD_HHMM("yyyyMMdd'#'HHmm"),
        // HH:mm
        TIME_HH_mm("HH:mm"),
        // HH:mm:ss
        TIME_HH_MM_SS("HH:mm:ss");

        private String value;

        Formatter(String value) {
            this.value = value;
        }

        public String getValue() {
            return value;
        }

        public static Formatter getByValue(String value) {
            Optional<Formatter> optional = Arrays.stream(values()).filter(p -> p.getValue() == value).findFirst();
            if (optional.isPresent()) {
                return optional.get();
            }
            return null;
        }
    }

    /**
     * LocalDateTime转String
     *
     * @param dateTime
     * @param formatter
     * @return
     */
    public static String format(LocalDateTime dateTime, Formatter formatter) {
        if (null == dateTime) {
            return null;
        }
        return dateTime.format(DateTimeFormatter.ofPattern(formatter.getValue()));
    }

    public static Calendar parseLocalDateTime2Calendar(LocalDateTime dateTime, Formatter formatter) {
        return parseFromStr2Calendar(format(dateTime, formatter), formatter);
    }


    /**
     * LocalTime转String
     *
     * @param dateTime
     * @param formatter
     * @return
     */
    public static String formatTime(LocalTime dateTime, Formatter formatter) {
        return dateTime.format(DateTimeFormatter.ofPattern(formatter.getValue()));
    }

    /**
     * LocalDate转String
     *
     * @param dateTime
     * @param formatter
     * @return
     */
    public static String formatDate(LocalDate dateTime, Formatter formatter) {
        return dateTime.format(DateTimeFormatter.ofPattern(formatter.getValue()));
    }
    public static String formatDateTime(LocalDateTime dateTime ) {
        return  format(dateTime, Formatter.DATETIME_YYYY_MM_DD_HH_MM_SS);
    }
    /**
     * 当前时间转String
     *
     * @param formatter
     * @return
     */
    public static String format(Formatter formatter) {
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(formatter.getValue()));
    }

    /**
     * String转LocalDateTime
     * 如果传的只有时间, 如08:00, 则尝试加上当前日期再转
     *
     * @param dateTime
     * @param formatter
     * @return
     */
    public static LocalDateTime parse(String dateTime, Formatter formatter) {
        try {
            if (StringUtils.isEmpty(dateTime)) {
                return null;
            }
            switch (formatter) {
                case TIME_HH_mm:
                case TIME_HH_MM_SS:
                    String nowDate = DateUtils.formatDate(LocalDate.now(), Formatter.DATE_YYYY_MM_DD);
                    return LocalDateTime.parse(String.format("%s %s", nowDate, dateTime),
                            DateTimeFormatter.ofPattern(String.format("%s %s", Formatter.DATE_YYYY_MM_DD.getValue(), formatter.getValue())));
                case DATE_YYYYMMDD:
                case DATE_YYYY_MM_DD:
                    return LocalDateTime.parse(String.format("%s 00:00:00", dateTime),
                            DateTimeFormatter.ofPattern(String.format("%s %s", formatter.getValue(), Formatter.TIME_HH_MM_SS.getValue())));
                case DATETIME_YYYYMMDDHHMM:
                case DATETIME_YYYYMMDDHHMMSS:
                case DATETIME_YYYY_MM_DD_HHMM:
                case DATETIME_YYYYMMDD_HHMM:
                case DATETIME_YYYYMMDD_HHMMSS:
                case DATETIME_YYYY_MM_DD_HH_MM:
                case DATETIME_YYYY_MM_DD_HH_MM_SS:
                case DATETIME_YYYY_MM_DD_HH_MM_SS_SSS:
                    return LocalDateTime.parse(dateTime, DateTimeFormatter.ofPattern(formatter.getValue()));
                default:
                    return null;
            }
        } catch (Exception e) {
            return null;
        }
    }

    public static LocalTime parseTime(String dateTime, Formatter formatter) {
        try {
            return LocalTime.parse(dateTime, DateTimeFormatter.ofPattern(formatter.getValue()));
        } catch (Exception e) {
            return null;
        }
    }
    public static LocalDateTime parseDateTime(String dateTime) {
        return parse(dateTime,Formatter.DATETIME_YYYY_MM_DD_HH_MM_SS);
    }

    public static LocalDate parseDate(String dateTime, Formatter formatter) {
        try {
            return LocalDate.parse(dateTime, DateTimeFormatter.ofPattern(formatter.getValue()));
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * String转Calendar
     *
     * @param dateTime
     * @param formatter
     * @return
     */
    public static Calendar parseFromStr2Calendar(String dateTime, Formatter formatter) {
        SimpleDateFormat sdf = new SimpleDateFormat(formatter.getValue());
        try {
            Date date = sdf.parse(dateTime);
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            return calendar;
        } catch (ParseException e) {
        }
        return null;

    }

    /**
     * 返回给定DateTime增加added后的日期
     *
     * @param dateTime
     * @param added
     * @param unit
     * @return
     */
    public static LocalDateTime getFutureDateTime(LocalDateTime dateTime, long added, DateUnit unit) {
        switch (unit) {
            case YEAR:
                return dateTime.plusYears(added);
            case MONTH:
                return dateTime.plusMonths(added);
            case DAY:
                return dateTime.plusDays(added);
            case HOUR:
                return dateTime.plusHours(added);
            case MINUTE:
                return dateTime.plusMinutes(added);
            case SECOND:
                return dateTime.plusSeconds(added);
            default:
                return null;
        }

    }

    /**
     * 返回当前日期增加added后的日期
     *
     * @param added
     * @param unit
     * @return
     */
    public static LocalDateTime getFutureDateTime(long added, DateUnit unit) {
        switch (unit) {
            case YEAR:
                return LocalDateTime.now().plusYears(added);
            case MONTH:
                return LocalDateTime.now().plusMonths(added);
            case DAY:
                return LocalDateTime.now().plusDays(added);
            case HOUR:
                return LocalDateTime.now().plusHours(added);
            case MINUTE:
                return LocalDateTime.now().plusMinutes(added);
            case SECOND:
                return LocalDateTime.now().plusSeconds(added);
            case MILLIS:
                return LocalDateTime.now().plus(added, ChronoUnit.MILLIS);
            default:
                return null;
        }

    }

    /**
     * 获取当前时间戳(毫秒)
     *
     * @return
     */
    public static long getCurrentTimestamp() {
        return LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
    }

    private static Float getTemporalDiffrence(Temporal start, Temporal end, DateUnit unit) {
        switch (unit) {
            case DAY:
                Long day = Duration.between(start, end).toDays();
                return day.floatValue();
            case HOUR:
                Long hour = Duration.between(start, end).toHours();
                return hour.floatValue();
            case MINUTE:
                Long minute = Duration.between(start, end).toMinutes();
                return minute.floatValue();
            case SECOND:
                return Duration.between(start, end).toMillis() / 1000f;
            case MILLIS:
                Long millis = Duration.between(start, end).toMillis();
                return millis.floatValue();
            default:
                return null;
        }
    }

    /**
     * 计算两个时间的间隔
     *
     * @param start
     * @param end
     * @param unit
     * @return
     */
    public static Float getLocalDateTimeDiffrence(LocalDateTime start, LocalDateTime end, DateUnit unit) {
        return getTemporalDiffrence(start, end, unit);
    }

    public static Float getLocalTimeDiffrence(LocalTime start, LocalTime end, DateUnit unit) {
        return getTemporalDiffrence(start, end, unit);
    }

    /**
     * firstDateTime是否早于secondDateTime
     *
     * @param startDateTime
     * @param endDateTime
     * @param formatter
     * @return
     */
    public static boolean isBefore(String startDateTime, String endDateTime, Formatter formatter) {
        return parse(startDateTime, formatter).isBefore(parse(endDateTime, formatter));
    }

    /**
     * dateTime是否早于当前时间
     *
     * @param dateTime
     * @param formatter
     * @return
     */
    public static boolean isBeforeNow(String dateTime, Formatter formatter) {
        return parse(dateTime, formatter).isBefore(LocalDateTime.now());
    }

    /**
     * 获取指定单位的值
     *
     * @param dateTime
     * @param formatter
     * @param unit
     * @return
     */
    public static Integer getValueByUnit(String dateTime, Formatter formatter, DateUnit unit) {
        switch (unit) {
            case YEAR:
                return parse(dateTime, formatter).getYear();
            case MONTH:
                return parse(dateTime, formatter).getMonthValue();
            case DAY:
                return parse(dateTime, formatter).getDayOfMonth();
            case HOUR:
                return parse(dateTime, formatter).getHour();
            case MINUTE:
                return parse(dateTime, formatter).getMinute();
            case SECOND:
                return parse(dateTime, formatter).getSecond();
            default:
                return null;
        }
    }

    /**
     * @param localDateTime
     * @param unit
     * @return
     */
    public static Integer getValueByUnit(LocalDateTime localDateTime, DateUnit unit) {
        switch (unit) {
            case YEAR:
                return localDateTime.getYear();
            case MONTH:
                return localDateTime.getMonthValue();
            case DAY:
                return localDateTime.getDayOfMonth();
            case HOUR:
                return localDateTime.getHour();
            case MINUTE:
                return localDateTime.getMinute();
            case SECOND:
                return localDateTime.getSecond();
            default:
                return null;
        }
    }

    public static long ldtToUnixTime(LocalDateTime localDateTime) {
        return localDateTime.toInstant(ZoneOffset.of("+8")).getEpochSecond();
    }

    /**
     * 转换日期的格式
     *
     * @param dateStr
     * @param originFormatter 原始格式
     * @param targetFormatter 需要转换后的格式
     * @return
     */
    public static String changeFormat(String dateStr, Formatter originFormatter, Formatter targetFormatter) {
        try {
            return format(parse(dateStr, originFormatter), targetFormatter);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * localdate _> date
     *
     * @param localDate
     * @return
     */
    public static Date localDate2Date(LocalDate localDate) {
        ZonedDateTime zonedDateTime = localDate.atStartOfDay(ZoneId.systemDefault());
        Instant instant1 = zonedDateTime.toInstant();
        Date from = Date.from(instant1);
        return from;
    }

    /**
     * 时间戳转LocalDateTime
     *
     * @param timestampStr
     * @return
     */
    public static LocalDateTime longToLocalDateTime(long timestampStr) {
        return LocalDateTime.ofEpochSecond(timestampStr / 1000, 0, ZoneOffset.ofHours(8));
    }

    /**
     * LocalDateTime转时间戳
     *
     * @param localDateTime
     * @return
     */
    public static long localDateTimeToLong(LocalDateTime localDateTime) {

        return localDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli();
    }

    public static void main(String[] args) {
        //System.out.println(DateUtils.getFutureDateTime(RandomUtil.getInteger(1314, 4321), DateUnit.MILLIS).getNano());
        String start = "2020-12-01";
        LocalTime startDate = LocalTime.of(5, 30);
        System.out.println(getLocalTimeDiffrence(startDate, LocalTime.now(), DateUnit.HOUR));
    }

}

